package order

import (
	"errors"
	"fmt"
	"math"
	"parking-lot-go-admin/model"
	"sort"
	"time"
)

type OrderStruct struct {
	Id             int       `gorm:"type:int(11) auto_increment; NOT NULL; primary_key"`
	StaticParkCode string    `gorm:"type:varchar(20); COMMENT:'静态停车场编号'"`
	ParkCode       string    `gorm:"type:varchar(20); COMMENT:'停车场编号'"`
	CarNumber      string    `gorm:"type:varchar(20); COMMENT:'车牌号'"`
	CarNoColor     int       `gorm:"type:tinyint(1); COMMENT:'车牌颜色 1-蓝牌 3-黄牌 6-绿牌 7-白牌 8-黑牌'"`
	CarType        int       `gorm:"type:tinyint(1); COMMENT:'车型 1: 小型车 2: 中型车 3: 大型车 4: 其 他'"`
	OrderNo        string    `gorm:"type:varchar(255); COMMENT:'系统单号'"`
	Status         int       `gorm:"type:tinyint(1); COMMENT:'订单状态 0 预约中, 1在场地内  2已结束'"`
	OrderType      int       `gorm:"type:tinyint(1); COMMENT:'1 小强停车'"`
	InTime         time.Time `gorm:"type:datetime;"`
	OutTime        time.Time `gorm:"type:datetime;"`
	CreatedAt      time.Time `gorm:"type:datetime"`
	UpdatedAt      time.Time `gorm:"type:datetime"`
	OperateAdminId int       `gorm:"type:int(11); COMMENT:'1 人工操作出场'"`
	Count          int       `gorm:"find_in_time_count"`
}
type ParkingHour struct {
	Hour  string
	Count int
}

func (c *OrderStruct) TableName() string {
	return "order"
}

// 时段停车计算
func (c *OrderStruct) TimeSlot(orderType int) []int {

	findStartTime := time.Now().Format("2006-01-02 00:00:00")

	var orderData []OrderStruct
	db := model.Db

	if orderType != -1 {
		//查询某个类型
		db.Debug().Raw("SELECT * FROM `order` WHERE `status` = 1 and order_type = ?"+
			" UNION "+
			"SELECT * FROM `order` WHERE `status` = 2  and order_type = ? AND out_time >= ?", orderType, orderType, findStartTime).Scan(&orderData)
	} else {

		//查询所有
		db.Debug().Raw("SELECT * FROM `order` WHERE `status` = 1 "+
			" UNION "+
			"SELECT * FROM `order` WHERE `status` = 2   AND out_time >= ?", findStartTime).Scan(&orderData)
	}

	//当前小时
	currentHour := time.Now().Hour()
	hours := make([]int, currentHour+1)
	for i := 0; i <= currentHour; i++ {
		hours[i] = 0
	}
	for _, v := range orderData {
		//结束递增时间
		endIncHour := currentHour
		if v.Status == 2 {
			endIncHour = v.OutTime.Hour()
		}

		//循环 增加数量
		for i := 0; i <= endIncHour; i++ {
			hours[i]++
		}
	}

	return hours
}

// 区间在场车辆
func (c *OrderStruct) IntervalPresence(startTime, endTime string, findType string, orderType int) []ParkingHour {
	where := map[string]interface{}{}

	if orderType != -1 {
		where["order_type"] = orderType
	}

	var orderData []OrderStruct
	model.GetModelData(model.Db,
		c.TableName(),
		&orderData,
		model.QueryOptions{
			SelectedFields: []string{"in_time", "out_time"},
			Conditions:     where,
			Debug:          true,
			OrderBy:        "id asc",
		})

	loc, _ := time.LoadLocation("Asia/Shanghai")

	//开始时间格式化
	startTimeFormat, _ := time.ParseInLocation("2006-01-02 15:04:05", startTime, loc)
	//结束时间格式化
	endTimeFormat, _ := time.ParseInLocation("2006-01-02 15:04:05", endTime, loc)

	// 创建一个 map 用于存储每一天停车场内的车辆数量
	parkingCount := make(map[string]int)

	for _, v := range orderData {
		// 检查停车记录是否在查询时间范围内
		if v.InTime.Before(endTimeFormat) && v.OutTime.After(startTimeFormat) {
			// 限制停车记录的入场时间和离场时间在查询时间范围内
			entryTime := v.InTime
			exitTime := v.OutTime
			if entryTime.Before(startTimeFormat) {
				entryTime = startTimeFormat
			}
			if exitTime.After(endTimeFormat) {
				exitTime = endTimeFormat
			}

			// 计算停车小时数
			hours := int(math.Ceil((exitTime.Sub(entryTime).Hours())))

			// 循环遍历每一个小时
			for i := 0; i < hours; i++ {
				// 添加一个小时的时间
				currentHour := entryTime.Add(time.Duration(i) * time.Hour)
				// 构造当前循环的年份、月份、日期和小时
				hourKey := currentHour.Format("15")
				// 判断是否已经存在该小时的停车记录
				parkingCount[hourKey]++
			}
		}
	}

	// 提取对象的键，并放入切片中
	keys := make([]string, 0, len(parkingCount))
	for key := range parkingCount {
		keys = append(keys, key)
	}

	// 对键进行排序（正序）
	sort.Strings(keys)

	// 创建一个结构体切片来存储排序后的键和对应的值
	sortedParking := make([]ParkingHour, 0, len(keys))

	// 将排序后的键和对应的值放入结构体切片中
	for _, key := range keys {
		count := parkingCount[key]
		ph := ParkingHour{Hour: key, Count: count}
		sortedParking = append(sortedParking, ph)
	}

	return sortedParking
}

// 今日在场车辆
func (c *OrderStruct) TodayInPark() (int, error) {

	db := model.Db

	//时间格式化
	todayFormat := time.Now().Format("2006-01-02 00:00:00")

	//当前在场
	var todayInCount int64
	if err := db.
		Table(c.TableName()).
		Where("status = ?", 1).
		Count(&todayInCount).
		Error; err != nil {
		return 0, errors.New(fmt.Sprintf("查询当前在场错误:%s", err.Error()))
	}

	//历史进场 今天出场
	var inParkedTodayOut int64
	if err := db.
		Table(c.TableName()).
		Where("out_time >= ?", todayFormat).
		Where("status = ?", 2).
		Count(&inParkedTodayOut).Error; err != nil {
		return 0, errors.New(fmt.Sprintf("查询今日出场错误:%s", err.Error()))
	}

	count64 := todayInCount + inParkedTodayOut

	count := int(count64)

	return count, nil
}

// 区间在场
func (c *OrderStruct) SectionInPark() ([]int, error) {
	db := model.Db

	var intArr []int

	// 获取当前时间
	now := time.Now()

	// 计算8天前的时间
	eightDaysAgo := now.AddDate(0, 0, -8)

	// 设置循环开始时间为8天前
	currentTime := eightDaysAgo

	// 循环遍历从8天前到昨天的时间
	for currentTime.Before(now.AddDate(0, 0, -1)) {
		findStartTime := currentTime.Format("2006-01-02 00:00:00")

		//当前还在场内, 并且 在指定日期之前进场
		var dateInCount int64
		if err := db.
			Table(c.TableName()).
			Where("in_time <= ?", findStartTime).
			Where("status = ?", 1).
			Count(&dateInCount).
			Error; err != nil {
			return intArr, errors.New(fmt.Sprintf("查询在场错误:%s", err.Error()))
		}

		//在指定日期之前进场 并且在指定日期后出场
		var dateCountCount int64
		if err := db.
			Table(c.TableName()).
			Where("in_time <= ?", findStartTime).
			Where("out_time >= ?", findStartTime).
			Where("status = ?", 2).
			Count(&dateCountCount).Error; err != nil {
			return intArr, errors.New(fmt.Sprintf("查询出场错误:%s", err.Error()))
		}

		dayCount := int(dateInCount + dateCountCount)
		intArr = append(intArr, dayCount)

		// 增加一天
		currentTime = currentTime.AddDate(0, 0, 1)
	}

	fmt.Println(intArr)

	return intArr, nil
}
